home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 2 / MacMania 2.toast / Demo's / Music⁄Sounds / BeepSay 1.0.1 / Resident.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-09  |  14.1 KB  |  646 lines  |  [TEXT/MPS ]

  1. /******************************************************************************
  2. **
  3. **  Folder Name:    BS
  4. **     File Name:    Resident.c
  5. **
  6. **   Copyright:    © 1993 by Siren Enterprises, all rights reserved.
  7. **
  8. **   Description:    Resident code segment for Lil´ BeepSay
  9. **
  10. *******************************************************************************
  11. **                       A U T H O R   I D E N T I T Y
  12. *******************************************************************************
  13. **
  14. **    Initials    Name
  15. **    --------    -----------------------------------------------
  16. **    kw            Ken Wieschhoff
  17. **
  18. *******************************************************************************
  19. **                      R E V I S I O N   H I S T O R Y
  20. *******************************************************************************
  21. **
  22. **      Date        Time    Author    Description
  23. **    --------    -----    ------    ---------------------------------------------
  24. **    05/17/93    17:44    kw        Original version
  25. **
  26. ******************************************************************************/
  27.  
  28. #include    <Traps.h>
  29. #include    <GestaltEqu.h>
  30. #include    <Notification.h>
  31. #include    <PLStringFuncs.h>
  32. #include    <Quickdraw.h>
  33. #include    <Packages.h>
  34. #include    <errors.h>
  35. #include    <AppleEvents.h>
  36. #include    "Resident.h"
  37. #include    "Preferences.h"
  38. #include    "Utilities.h"
  39.  
  40.  
  41. #define        BTstQ(arg, bitnbr)        (arg & (1 << bitnbr))
  42. #define        kDoAsync    true
  43.  
  44. Str255            gFileName;
  45. short            gFileVolume;
  46. long            gFileDirID;
  47. PreferencesHdl    gPrefs = nil;
  48.  
  49. pascal OSErr     ReadPreferences();
  50. pascal OSErr     OurGestaltFunc( OSType selector, long *response);
  51. pascal void        OurSysBeep(short duration);
  52. OSErr            InstallGestalt( void);
  53. pascal OSErr     _MAIN( StringPtr fileName, short volume, long dirID);
  54. pascal void     ShowStr( StringPtr str);
  55. pascal void     ShowStrNum( StringPtr str, OSErr err);
  56. pascal void        _OurSysBeep(short duration);
  57. OSErr            InitAppleEvents();
  58. pascal OSErr     OurSpeakTheText(StringPtr itsText, Boolean async);
  59. pascal OSErr     AESetBeepSayState(AppleEvent *messagein, AppleEvent *reply, long refIn);
  60. pascal OSErr     AESpeakBeepSayPhrase(AppleEvent *messagein, AppleEvent *reply, long refIn);
  61.  
  62.  
  63. pascal OSErr MAIN( StringPtr fileName, short volume, long dirID)
  64. {
  65.     Handle    newA5;
  66.     OSErr     err;
  67.     long    hostA5;
  68.     
  69.     hostA5 = GetA5();
  70.  
  71.     newA5 = NewHandle( 0); // Handle for globals
  72.     if( !newA5)
  73.         return (memFullErr);
  74.  
  75.     // Make a new A5 world.
  76.     err = MakeA5World( newA5); // Sizes the Handle
  77.     if( err != noErr) {
  78.         DisposeHandle( newA5);
  79.         newA5 = nil;
  80.         return ( err);
  81.     }
  82.     
  83.     *OldA5() = (long) newA5;
  84.     FlushInstructionCache();        // '040 Compatibility
  85.     FlushDataCache();
  86.     
  87.     SetA5((long)StripAddress((*newA5)) + A5Size() - 32);
  88.  
  89.     // Do the work
  90.     err = _MAIN(  fileName, volume, dirID);
  91.  
  92.     // Restore the A5
  93.     RestoreA5World( hostA5);
  94.     
  95.     return ( err);
  96.  
  97. }
  98.  
  99. pascal OSErr _MAIN( StringPtr fileName, short volume, long dirID)
  100. {
  101.     short    err = noErr;
  102.     
  103.  
  104.     // Install system traps, etc.
  105.     InitGraf( &qd.thePort);
  106.     
  107.     /*
  108.         Remember supplied file info (unused so far but useful if we need to
  109.         get resources from the cdev)
  110.     */
  111.     PLstrcpy( gFileName, fileName);
  112.     gFileVolume = volume;
  113.     gFileDirID = dirID;
  114.  
  115.     // Read the current preferences.  File will be created if it doesn't exist.
  116.     err = _ReadPreferences( &gPrefs, kBeepSayPrefs);
  117.     if ( err != noErr)
  118.         goto exit;
  119.  
  120.     // Install our Gestalt function.
  121.     err = InstallGestalt();
  122.     if ( err != noErr)
  123.         goto exit;
  124.  
  125.     err = InstallTrap();
  126.  
  127.     if ( err != noErr)
  128.         goto exit;
  129.  
  130.     // Add our Apple Event Handlers
  131.     err = InitAppleEvents();
  132. exit:    
  133.     
  134.     return( err);
  135. }
  136.  
  137.  
  138. TrapType GetTrapType(short theTrap)
  139.  
  140. {
  141.     // OS traps start with A0, Tool with A8 or AA. 
  142.     if ((theTrap & 0x0800) == 0)                // per D.A.
  143.         return OSTrap;
  144.     else
  145.         return ToolTrap;
  146. } // GetTrapType 
  147.  
  148.  
  149.  
  150. pascal OSErr InstallTrap( void)
  151. {
  152.  
  153.     Ptr        newSysbeep = (Ptr) &OurSysBeep;
  154.  
  155.     (*OldSysBeep()) = NGetTrapAddress( _SysBeep, GetTrapType( _SysBeep));
  156.     FlushInstructionCache();    // '040 Compatibility
  157.     FlushDataCache();
  158.     NSetTrapAddress( (long) StripAddress( newSysbeep ), _SysBeep, 
  159.                         GetTrapType( _SysBeep));
  160.     return( noErr);
  161. }
  162.  
  163. OSErr    InstallGestalt( void)
  164. {
  165.     short err;
  166.     
  167.     
  168.     err = NewGestalt(cKBPSAChangedResource, (ProcPtr) StripAddress((Ptr) &OurGestaltFunc));
  169.     return( err);
  170. }
  171.  
  172. // InitAEStuff installs the appleevent handlers
  173. OSErr InitAppleEvents(void)
  174. {
  175.     struct AEinstalls {
  176.         AEEventClass theClass;
  177.         AEEventID theEvent;
  178.         EventHandlerProcPtr theProc;
  179.     } HandlersToInstall[] =  {
  180.         {
  181.             kBeepSaySignature, kBeepSaySetState, AESetBeepSayState
  182.         },  {
  183.             kBeepSaySignature, kBeepSaySpeakPhrase, AESpeakBeepSayPhrase
  184.         }, 
  185.         
  186.     };
  187.     typedef struct AEinstalls AEinstalls; 
  188.     
  189.     OSErr     aevtErr = noErr;
  190.     long     aLong = 0;
  191.     Boolean    hasAppleEvents = false;
  192.     short     index;
  193.  
  194.  
  195.     // Check for AppleEvents
  196.     aevtErr = Gestalt(gestaltAppleEventsAttr, &aLong);
  197.     if (aevtErr) 
  198.         return (aevtErr);
  199.  
  200.     // Install Handlers in System Heap.
  201.     for (index = 0; index < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); index++) {
  202.         aevtErr = AEInstallEventHandler(HandlersToInstall[index].theClass, 
  203.                 HandlersToInstall[index].theEvent,
  204.                                         HandlersToInstall[index].theProc, 0, true);
  205.         if (aevtErr) 
  206.             return (aevtErr);
  207.     }
  208.  
  209.     return ( noErr);
  210. }
  211.  
  212. pascal void    OurSysBeep(short duration)
  213. {
  214.     long    hostA5;
  215.     Handle    ourA5 = *OldA5();
  216.  
  217.     hostA5 = GetA5();
  218.  
  219.     // Set up our globals.
  220.     SetA5((long)StripAddress((*ourA5)) + A5Size() - 32);
  221.  
  222.     // Call our trap
  223.     _OurSysBeep( duration);
  224.  
  225.     // Restore the A5
  226.     RestoreA5World( hostA5);
  227.  
  228. }
  229.  
  230. pascal void OurEndOfSpeechCallBack( SpeechChannel channel, long refCon)
  231. {
  232. #    pragma unused(refCon)
  233.  
  234.     (void)DisposeSpeechChannel( channel);
  235.         
  236. }
  237.  
  238. pascal void    _OurSysBeep(short duration)
  239. {
  240.     OSErr             err = -1;
  241.     long            result;
  242.     long            timeOut;
  243.     short            numChannels = 0;
  244.     
  245.     // Is it on??
  246.     if ( !(**gPrefs).on_off) {
  247.         CallOldSysBeep(duration);
  248.         return;
  249.     }
  250.  
  251.     // Is the speech manager available?
  252.     err = Gestalt( gestaltSpeechAttr, &result);
  253.     if ((err != noErr) || !(result &  (1 << gestaltSpeechMgrPresent))) {
  254.         CallOldSysBeep( duration);
  255.         return;
  256.     }
  257.  
  258.     // Wait for an available channel for 6 seconds.
  259.     if ( (**gPrefs).onlyPlayOne) {
  260.         timeOut = TickCount() + 360;
  261.         while( ((numChannels = SpeechBusySystemWide()) > 0) && (TickCount() < timeOut))
  262.         {
  263.         }    // wait for it.
  264.  
  265.         if ( numChannels > 0) {
  266.             CallOldSysBeep( duration);
  267.             return;
  268.         }
  269.  
  270.     }
  271.     
  272.     // Lock the preferences handle
  273.     HLock( (Handle) gPrefs);
  274.     err = OurSpeakTheText( (**gPrefs).theText, kDoAsync);
  275.     HUnlock( (Handle) gPrefs);
  276.  
  277.     if ( err != noErr) {
  278.         CallOldSysBeep( duration);
  279.         return;
  280.     }
  281.  
  282.     return;
  283.  
  284. }
  285.  
  286. typedef pascal void (*ourSysBeepPtr)(short duration);
  287. pascal void CallOldSysBeep(duration)
  288. {
  289.     ourSysBeepPtr    trap;
  290.     
  291.     // Retrieve the old trap.
  292.     trap = (ourSysBeepPtr) *OldSysBeep();
  293.     
  294.     // Call prior SysBeep
  295.     (*trap)(duration);
  296.  
  297.     return;
  298.  
  299. }
  300.  
  301. pascal OSErr     _OurGestaltFunc( OSType selector, long *response)
  302. {
  303.     short    err = noErr;
  304.  
  305.     *response = 0;
  306.     
  307.     switch( selector) {
  308.     
  309.         case cKBPSAChangedResource:        // Preferences Changed
  310.             
  311.             *response = (long *) ReadPreferences;
  312.             break;
  313.  
  314.         default:
  315.             err = gestaltUndefSelectorErr;
  316.             break;
  317.         
  318.     }
  319.     
  320. exit:
  321.     
  322.     return( err);
  323. }
  324.  
  325. pascal OSErr     OurGestaltFunc( OSType selector, long *response)
  326. {
  327.     short    err;
  328.     long    hostA5;
  329.     Handle    ourA5 = *OldA5();
  330.     
  331.     hostA5 = GetA5();
  332.  
  333.     
  334.     SetA5((long)StripAddress((*ourA5)) + A5Size() - 32);
  335.  
  336.     // Do the work
  337.     err = _OurGestaltFunc( selector, response);
  338.  
  339.     // Restore the A5
  340.     RestoreA5World( hostA5);
  341.  
  342.     return( err);
  343. }
  344.  
  345. pascal OSErr     ResetPreferences()
  346. {
  347.     short            err;
  348.     Handle            ourA5 = *OldA5();
  349.     PreferencesHdl    itsPrefs = nil;
  350.     
  351.  
  352.     // Read the preferences from disk
  353.     err = _ReadPreferences( &itsPrefs, kBeepSayPrefs);
  354.     
  355.     // If no errors set the new preferences here.
  356.     if ( err == noErr) {
  357.         DisposeHandle( (Handle) gPrefs);
  358.         gPrefs = itsPrefs;
  359.     }
  360.  
  361.     return( err);
  362. }
  363.  
  364. pascal OSErr     ReadPreferences()
  365. {
  366.     short        err;
  367.     long        hostA5;
  368.     Handle        ourA5 = *OldA5();
  369.     
  370.     hostA5 = GetA5();
  371.  
  372.     
  373.     SetA5((long)StripAddress((*ourA5)) + A5Size() - 32);
  374.  
  375.     // Do the work
  376.     err = ResetPreferences();
  377.  
  378.     // Restore the A5
  379.     RestoreA5World( hostA5);
  380.  
  381.     return( err);
  382. }
  383.  
  384. pascal void ShowStrNum( StringPtr str, OSErr err)
  385. {
  386.     Str255    errText, strText;
  387.     
  388.     NumToString( (long) err, errText);
  389.     
  390.     PLstrcpy(strText, str);
  391.     PLstrcat(strText,"\p Error = ");
  392.     PLstrcat(strText, errText);
  393.     ShowStr( strText);
  394. }
  395.  
  396. pascal void _DisposeError( NMRec *theNMRec)
  397. {
  398.     OSErr    err;
  399.  
  400.     err = NMRemove( theNMRec);
  401.  
  402.     DisposePtr( (Ptr) theNMRec->nmStr );
  403.     DisposePtr( (Ptr) theNMRec );
  404. }
  405.  
  406. pascal void DisposeError( NMRec *theNMRec)
  407. {
  408.     long    hostA5;
  409.     Handle    ourA5 = *OldA5();
  410.     
  411.     hostA5 = GetA5();
  412.  
  413.     
  414.     SetA5((long)StripAddress((*ourA5)) + A5Size() - 32);
  415.  
  416.         _DisposeError( theNMRec);
  417.         
  418.     RestoreA5World( hostA5);
  419. }
  420.  
  421. pascal void ShowStr( StringPtr str)
  422. {
  423.     NMRec*        nmPtr;
  424.     StringPtr    text;
  425.     
  426.     // Call the Notification Manager to display errors.
  427.     nmPtr = (NMRec*) NewPtr( sizeof( NMRec) );
  428.     if ( nmPtr == nil) {
  429.         return;
  430.     }
  431.     text = (StringPtr) NewPtr( str[0] + 1);
  432.     if ( text == nil) {
  433.         DisposePtr( (Ptr) nmPtr);
  434.         return;
  435.     }
  436.     PLstrcpy( text, str);
  437.     
  438.     nmPtr->qType     = 8;        
  439.     nmPtr->nmMark     = 0;                        // no mark in application menu
  440.     nmPtr->nmIcon     = nil;                        // nil = no icon in menubar or a handle to SICN resource
  441.     nmPtr->nmSound    = (Handle)-1;                // pick a sound, use -1 for System Beep or nil for no sound.
  442.     nmPtr->nmStr     = text;                        // display this string in dialog
  443.     nmPtr->nmResp     = (NMProcPtr)DisposeError;    // Routine to dispose of the pointer block. (nil - Use default)
  444.     nmPtr->nmRefCon = 0L;                        // no refcon
  445.  
  446.     if( NMInstall( nmPtr) != noErr) {
  447.         DisposePtr( (Ptr) nmPtr);
  448.         DisposePtr( (Ptr) text);
  449.     }
  450. }
  451.  
  452. pascal OSErr OurSpeakTheText(StringPtr itsText, Boolean async)
  453. {
  454.     OSErr            err = -1;
  455.     long            timeOut = TickCount() + 180;
  456.     SpeechChannel    theChannel;
  457.     long    hostA5;
  458.     
  459.     hostA5 = GetA5();
  460.  
  461.     // Try for no more than 3 seconds to get a new speech channel.
  462.     while (( err != noErr)  && (TickCount() < timeOut))
  463.         err = NewSpeechChannel( &(**gPrefs).theVoice, &theChannel);
  464.  
  465.     if ( err != noErr)
  466.         return (err);
  467.  
  468.     // Set the speech rate and pitch.
  469.     (void)SetSpeechPitch( theChannel, (**gPrefs).thePitch);
  470.     (void)SetSpeechRate( theChannel, (**gPrefs).theRate);
  471.  
  472.     // Set our A5 world to use when using callbacks.
  473.     err = SetSpeechInfo( theChannel, soCurrentA5, &hostA5);
  474.  
  475.     if ( err != noErr)
  476.         return (err);
  477.     
  478.     // Set a callback to use to dispose the speech channel.
  479.     if ( async) {
  480.         err = SetSpeechInfo( theChannel, soSpeechDoneCallBack, &OurEndOfSpeechCallBack);
  481.  
  482.         if ( err != noErr)
  483.             return (err);
  484.     }
  485.  
  486.     // Speak the text.
  487.     err = SpeakText( theChannel, &itsText[1], itsText[0]);
  488.     
  489.     if ( async)
  490.         return (err);
  491.         
  492.     while( SpeechBusy() > 0)
  493.         {}    // Wait for the speech to complete.
  494.  
  495.  
  496.     return ( DisposeSpeechChannel( theChannel));
  497.     
  498.  
  499. }
  500.  
  501.  
  502. void AddToReply(AppleEvent *reply, Str255 theWords, long theError)
  503. {
  504.     OSErr         err = noErr;
  505.     long         errNo;
  506.     DescType     returnedType;
  507.     Size         returnedSize;
  508.     
  509.     // First, is there a reply hanging out?
  510.     if (reply) {
  511.         // test to see if there is one already
  512.         err = AEGetParamPtr(reply, keyErrorNumber, typeLongInteger, &returnedType, (Ptr)&errNo, sizeof(long),
  513.                               &returnedSize);
  514.         
  515.         if (err == errAEDescNotFound) {
  516.             // cool, press on.
  517.             err = AEPutParamPtr(reply, keyErrorNumber, typeLongInteger, (Ptr)&theError, sizeof(long));
  518.             if (!err)
  519.                 err = AEPutParamPtr(reply, keyErrorString, typeChar, (Ptr)&theWords[1], theWords[0]);
  520.             
  521.         }
  522.     }
  523. }
  524.  
  525. pascal OSErr _AESetBeepSayState(AppleEvent *messagein, AppleEvent *reply, long refIn)
  526. {
  527. #pragma unused ( refIn )
  528.  
  529.     Boolean            setState, currentState = (**gPrefs).on_off;
  530.     OSErr            err = noErr;
  531.     DescType        theDescType;
  532.     Size            theSize;
  533.     long            result;
  534.     
  535.     
  536.     // Get the state passed in.
  537.     err = AEGetParamPtr(messagein, keyDirectObject, typeBoolean, 
  538.             &theDescType, (Ptr) &setState, sizeof(setState), &theSize);
  539.  
  540.  
  541.     // Caller didn't send the boolean state parameter.
  542.     if (err != noErr) {
  543.         AddToReply( reply, "\p No boolean state was sent!", (long) err);
  544.         goto ErrExit;
  545.     }
  546.     else
  547.         (**gPrefs).on_off = setState;
  548.  
  549.     // Is the speech manager available?
  550.     err = Gestalt( gestaltSpeechAttr, &result);
  551.     if ((err != noErr) || !(result &  (1 << gestaltSpeechMgrPresent))) {
  552.         AddToReply( reply, "\p The Text To Speech Manager is not installed!", (long) err);
  553.     }
  554.  
  555.  
  556. ErrExit:
  557.     // Always return the current state
  558.     return(AEPutParamPtr(reply, keyDirectObject, typeBoolean, 
  559.             (Ptr) ¤tState, sizeof(currentState)));
  560. }
  561.  
  562. #pragma segment MAIN
  563. pascal OSErr AESetBeepSayState(AppleEvent *messagein, AppleEvent *reply, long refIn)
  564. {
  565.     long    hostA5;
  566.     Handle    ourA5 = *OldA5();
  567.     OSErr    err;
  568.     
  569.     hostA5 = GetA5();
  570.  
  571.     
  572.     SetA5((long)StripAddress((*ourA5)) + A5Size() - 32);
  573.  
  574.         err = _AESetBeepSayState( messagein, reply, refIn);
  575.         
  576.     RestoreA5World( hostA5);
  577.  
  578.     return ( err);
  579.  
  580. }
  581.  
  582. pascal OSErr _AESpeakBeepSayPhrase(AppleEvent *messagein, AppleEvent *reply, long refIn)
  583. {
  584. #pragma unused ( refIn )
  585.  
  586.     Str255            theText;
  587.     OSErr            err = noErr;
  588.     DescType        theDescType;
  589.     Size            theSize;
  590.     long            result;
  591.     VoiceSpec        undefinedVoice;
  592.     
  593.     (void) MakeVoiceSpec('????', '????', &undefinedVoice);
  594.     
  595.     if ( undefinedVoice == (**gPrefs).theVoice) {
  596.         AddToReply( reply, "\pLil´ BeepSay must be configured using the control panel prior to use!", 
  597.                 (long) abortErr);
  598.         goto ErrExit;
  599.     }
  600.  
  601.     // Get the character string to speak
  602.     err = AEGetParamPtr(messagein, keyDirectObject, typeChar, 
  603.             &theDescType, (Ptr) &theText[1], sizeof(theText), &theSize);
  604.  
  605.  
  606.     // Caller didn't send the bloody phrase.
  607.     if (err != noErr) {
  608.         AddToReply( reply, "\p No phrase was sent to speak!", (long) err);
  609.         goto ErrExit;
  610.     }
  611.  
  612.     // Is the speech manager available?
  613.     err = Gestalt( gestaltSpeechAttr, &result);
  614.     if ((err != noErr) || !(result &  (1 << gestaltSpeechMgrPresent))) {
  615.         AddToReply( reply, "\p The Text To Speech Manager is not installed!", (long) err);
  616.         goto ErrExit;
  617.     }
  618.  
  619.     theText[0] = (char) theSize;
  620.     err = OurSpeakTheText(theText, !kDoAsync); // Complete the phrase.
  621.     if ( err != noErr) 
  622.         AddToReply( reply, "\p Couldn't speak the phrase!", (long) err);
  623.  
  624. ErrExit:
  625.     return(err);
  626. }
  627.  
  628. pascal OSErr AESpeakBeepSayPhrase(AppleEvent *messagein, AppleEvent *reply, long refIn)
  629. {
  630.     long    hostA5;
  631.     Handle    ourA5 = *OldA5();
  632.     OSErr    err;
  633.     
  634.     hostA5 = GetA5();
  635.  
  636.     
  637.     SetA5((long)StripAddress((*ourA5)) + A5Size() - 32);
  638.  
  639.         err = _AESpeakBeepSayPhrase( messagein, reply, refIn);
  640.         
  641.     RestoreA5World( hostA5);
  642.  
  643.     return ( err);
  644.  
  645. }
  646.